package com.googlecode.horncomb.web.spring.tags;

import javax.servlet.jsp.JspException;

import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.tags.form.AbstractHtmlElementTag;
import org.springframework.web.servlet.tags.form.TagWriter;

import com.googlecode.horncomb.web.util.TagUtils;

public class SecurityLabelTag extends AbstractHtmlElementTag {
	private static final long serialVersionUID = -8441739627467717501L;
	/**
	 * The HTML '<code>label</code>' tag.
	 */
	private static final String LABEL_TAG = "label";

	/**
	 * The name of the '<code>for</code>' attribute.
	 */
	private static final String FOR_ATTRIBUTE = "for";

	/**
	 * The {@link TagWriter} instance being used.
	 * <p>
	 * Stored so we can close the tag on {@link #doEndTag()}.
	 */
	private TagWriter tagWriter;

	/**
	 * The value of the '<code>for</code>' attribute.
	 */
	private String forId;

	private static final Double defaultPermission = 9999d;
	private String permission = null;
	private String required = "false";

	/**
	 * Writes the opening '<code>label</code>' tag and forces a block tag so
	 * that body content is written correctly.
	 * @return {@link javax.servlet.jsp.tagext.Tag#EVAL_BODY_INCLUDE}
	 */
	protected int writeTagContent(TagWriter tagWriter) throws JspException {
		tagWriter.startTag(LABEL_TAG);
		String htmlFor = resolveFor();
		tagWriter.writeAttribute(FOR_ATTRIBUTE, htmlFor == null ? "" : htmlFor);
		writeDefaultAttributes(tagWriter);
		tagWriter.forceBlock();

		this.tagWriter = tagWriter;
		// 输出红色*号标识必填
		if (this.getRequired()) {
			tagWriter.startTag("font");
			tagWriter.writeAttribute("color", "red");
			tagWriter.appendValue("*");
			tagWriter.endTag();
		}
		return EVAL_BODY_INCLUDE;
	}

	/**
	 * Overrides {@link #getName()} to always return the empty string "",
	 * because the '<code>name</code>' attribute is not supported by the '
	 * <code>label</code>' tag.
	 * @return the value for the HTML '<code>name</code>' attribute
	 */
	protected String getName() throws JspException {
		// This also suppresses the 'id' attribute (which is okay for a
		// <label/>)
		return "";
	}

	/**
	 * Returns the value that must be used for the '<code>for</code>' attribute.
	 */
	protected final String resolveFor() throws JspException {
		if (StringUtils.hasText(this.forId)) {
			return getDisplayString(evaluate(FOR_ATTRIBUTE, this.forId));
		} else {
			return getCompletePath();
		}
	}

	/**
	 * Close the '<code>label</code>' tag.
	 * @return {@link javax.servlet.jsp.tagext.Tag#EVAL_PAGE}
	 */
	public int doEndTag() throws JspException {
		this.tagWriter.endTag();
		return EVAL_PAGE;
	}

	/**
	 * Disposes of the {@link TagWriter} instance.
	 */
	public void doFinally() {
		super.doFinally();
		this.tagWriter = null;
	}

	/**
	 * @param permission
	 *            the permission to set
	 */
	public void setPermission(String permission) throws NumberFormatException,
			JspException {
		this.permission = permission;
	}

	/**
	 * @return
	 * @throws NumberFormatException
	 * @throws JspException
	 */
	protected Double getPermission() throws NumberFormatException, JspException {
		String pms = this.getDisplayString(this.evaluate("permission",
				this.permission));
		if (!StringUtils.hasText(pms)) {
			Object pagePrmsObj = this.pageContext
					.getAttribute(SecurityInputTag.PAGE_PERMISSION_KEY);
			if (pagePrmsObj != null) {
				pms = pagePrmsObj.toString();
			}
		}
		if (!StringUtils.hasText(pms)) {
			return defaultPermission;
		} else {
			return Double.parseDouble(pms);
		}
	}

	/**
	 * @param required
	 *            the required to set
	 */
	public void setRequired(String required) {
		this.required = required;
	}

	protected boolean getRequired() throws JspException {
		return TagUtils.getBooleanValue("required", this.required, pageContext);
	}

	/**
	 * Set the value of the '<code>for</code>' attribute.
	 * <p>
	 * Defaults to the value of {@link #getPath}; may be a runtime expression.
	 * @throws IllegalArgumentException
	 *             if the supplied value is <code>null</code>
	 */
	public void setFor(String forId) {
		Assert.notNull(forId, "'forId' must not be null");
		this.forId = forId;
	}

	/**
	 * Get the value of the '<code>id</code>' attribute.
	 * <p>
	 * May be a runtime expression.
	 */
	public String getFor() {
		return this.forId;
	}
}
